#pragma once
#include "../common/net.hpp"
#include "../common/message.hpp"

/*
提供Rpc请求处理回调函数
 内部的服务管理
 方法名称
 参数信息
 对外提供参数校验接⼝
*/

namespace rpc
{
    namespace server
    {
        enum class VType
        {
            BOOL = 0,//布尔
            INTEGRAL,//整数
            NUMERIC,//浮点
            STRING,//字符串
            ARRAY,//数组
            OBJECT//对象
        };

        //服务描述->方法名称,回调函数
        class ServiceDescribe
        {
        private:
            bool rtypeCheck(const Json::Value &val)
            {
                return check(_return_type, val);
            }

            //检查类型是否一致
            bool check(VType vtype, const Json::Value &val)
            {  
                switch (vtype)
                {
                case VType::BOOL:
                    return val.isBool();
                case VType::INTEGRAL:
                    return val.isIntegral();
                case VType::NUMERIC:
                    return val.isNumeric();
                case VType::STRING:
                    return val.isString();
                case VType::ARRAY:
                    return val.isArray();
                case VType::OBJECT:
                    return val.isObject();
                }
                return false;
            }

        public:
            using ptr = std::shared_ptr<ServiceDescribe>;
            using ServiceCallback = std::function<void(const Json::Value &, Json::Value &)>;//Json请求,Json响应
            using ParamsDescribe = std::pair<std::string, VType>;//参数字段名称:参数字段类型
            ServiceDescribe(const std::string &&mname, const std::vector<ParamsDescribe> &&desc, VType vtype, const ServiceCallback &&handler) :
            _method_name(std::move(mname)),                                     
            _callback(std::move(handler)),                                            
            _params_desc(std::move(desc)), 
            _return_type(vtype)
            {
            }
            const std::string &method()
            {
                return _method_name;
            }

            //对rcp请求参数进行校验
            bool paramCheck(const Json::Value &params)//对params进行参数校验->判断描述的参数字段是否存在,类型是否一致
            {
                //对参数进行校验
                for (auto &desc : _params_desc)
                {
                    if (params.isMember(desc.first) == false)
                    {
                        LOG(ERROR, "参数字段完整性校验失败,%s字段缺失", desc.first.c_str());
                        return false;
                    }
                    //判断类型是否一致
                    if (check(desc.second, params[desc.first]) == false)
                    {
                        LOG(ERROR, "%s参数类型校验失败", desc.first.c_str());
                        return false;
                    }
                }
                return true;
            }

            //调用回调函数
            bool call(const Json::Value &params, Json::Value &result)
            {
                _callback(params, result);
                if (rtypeCheck(result) == false)
                {
                    LOG(ERROR, "回调处理函数中的响应信息校验失败");
                    return false;
                }
                return true;
            }

        private:
            std::string _method_name;//方法名称
            ServiceCallback _callback;//实际业务回调函数
            std::vector<ParamsDescribe> _params_desc;//参数格式描述  params{num1:int,num2:int}
            VType _return_type;//返回值类型
        };

        //工厂模式->生产describe
        //建造者模式->先建造成功,再进行创建Describe->解决线程安全问题
        class SDescribeFactory
        {
        public:
            void setMethodName(const std::string &name)
            {
                _method_name = name;
            }

            void setReturnType(VType vtype)
            {
                _return_type = vtype;
            }

            void setParamsDesc(const std::string &pname, VType vtype)
            {
                _params_desc.push_back(ServiceDescribe::ParamsDescribe(pname, vtype));
            }

            void setCallback(const ServiceDescribe::ServiceCallback &cb)
            {
                _callback = cb;
            }

            //进行建造
            ServiceDescribe::ptr build()
            {
                return std::make_shared<ServiceDescribe>(std::move(_method_name),
                                                         std::move(_params_desc), _return_type, std::move(_callback));
            }
        private:
            std::string _method_name;
            ServiceDescribe::ServiceCallback _callback;
            std::vector<ServiceDescribe::ParamsDescribe> _params_desc;
            VType _return_type;
        };

        //服务管理,封装增删查等
        class ServiceManager
        {
        public:
            using ptr = std::shared_ptr<ServiceManager>;
            void insert(const ServiceDescribe::ptr &desc) //插入
            {
                std::unique_lock<std::mutex> lock(_mutex);
                _services.insert(std::make_pair(desc->method(), desc));
            }

            ServiceDescribe::ptr select(const std::string &method_name) //查找
            {
                std::unique_lock<std::mutex> lock(_mutex);
                auto it = _services.find(method_name);
                if (it == _services.end())
                {
                    return ServiceDescribe::ptr();
                }
                return it->second;
            }

            void remove(const std::string &method_name) //删除
            {
                std::unique_lock<std::mutex> lock(_mutex);
                _services.erase(method_name);
            }

        private:
            std::mutex _mutex;
            std::unordered_map<std::string, ServiceDescribe::ptr> _services;//方法名:对应的服务描述
        };

        //Rpc注册接口,给disptacher提供的请求处理函数
        class RpcRouter
        {
        private:
            //进行响应的发送
            void response(const BaseConnection::ptr &conn, const RpcRequest::ptr &req, const Json::Value &res, RCode rcode)
            {
                auto msg = MessageFactory::create<RpcResponse>();
                msg->setId(req->rid());
                msg->setMType(rpc::MType::RSP_RPC);
                msg->setRCode(rcode);
                msg->setResult(res);
                conn->send(msg);
            }

        public:
            using ptr = std::shared_ptr<RpcRouter>;
            RpcRouter() : _service_manager(std::make_shared<ServiceManager>()) {}

            //提供给dispatcher模块,rpc请求进行回调的业务函数
            void onRpcRequest(const BaseConnection::ptr &conn, RpcRequest::ptr &request)
            {
                //获取服务对象
                auto service = _service_manager->select(request->method());
                if (service.get() == nullptr)
                {
                    LOG(ERROR, "%s 服务未找到", request->method().c_str());
                    return response(conn, request, Json::Value(), RCode::RCODE_NOT_FOUND_SERVICE);
                }
                if (service->paramCheck(request->params()) == false)
                {
                    LOG(ERROR, "%s 服务参数校验失败", request->method().c_str());
                    return response(conn, request, Json::Value(), RCode::RCODE_INVALID_PARAMS);
                }
                Json::Value result;
                //进行调用
                bool ret = service->call(request->params(), result);
                if (ret == false)//返回类型错误
                {  
                    LOG(ERROR, "%s 服务参数校验失败", request->method().c_str());
                    return response(conn, request, Json::Value(), RCode::RCODE_INTERNAL_ERROR);
                }
                return response(conn, request, result, RCode::RCODE_OK);
            }

            //注册服务->直接给describe:外界用工厂进行创建
            void registerMethod(const ServiceDescribe::ptr &service)
            {
                return _service_manager->insert(service);
            }

        private:
            ServiceManager::ptr _service_manager;//服务管理对象
        };
    }
}


